package jch.learn.java.advanced.chapter1_stream.optional;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

// Optional<T> 类型
// Optional<T> 类型用来替代类型T的引用，该引用要么引用某个对象，要么为null。在正确使用的情况下才会更安全。
public class OptionalTest {

    public static void main(String[] args) throws IOException, URISyntaxException {
        String contents = new String(Files.readAllBytes(Paths.get(OptionalTest.class.getResource("/gutenberg/alice30.txt").toURI())), StandardCharsets.UTF_8);
        List<String> wordList = Arrays.asList(contents.split("\\PL+"));

        // java.util.Optional

        Optional<String> optionalValue = wordList.stream().filter(s -> s.contains("fred")).findFirst();
        // T orElse(T other)    产生该Optional的值，或者在该Optional为空时，产生other。
        System.out.println(optionalValue.orElse("No word") + " contains fred");

        // static <T> Optional<T> empty()   产生一个空的Optional
        Optional<String> optionalString = Optional.empty();
        String result = optionalString.orElse("N/A");
        System.out.println("result: " + result);

        // T orElseGet(Supplier<? extends T> other) 产生该Optional的值，或者Optional为空时，产生调用other的结果。
        result = optionalString.orElseGet(() -> Locale.getDefault().getDisplayName());
        System.out.println("result: " + result);

        try {
            // <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
            // 产生该Optional的值，或者在该Optional为空时，抛出调用exceptionSupplier的结果。
            result = optionalString.orElseThrow(IllegalStateException::new);
            System.out.println("result: " + result);
        } catch (Throwable t) {
            t.printStackTrace();
        }

        optionalValue = wordList.stream().filter(s -> s.contains("red")).findFirst();
        // void ifPresent(Consumer<? super T> consumer)  若该Optional不为空，则将它的值传递给consumer。
        optionalValue.ifPresent(s -> System.out.println(s + " contains red"));

        Set<String> results = new HashSet<>();
        optionalValue.ifPresent(results::add);
        // <U> Optional<U> map(Function<? super T,? extends U> mapper)
        // 产生该Optional的值传递给mapper后的结果，只要该Optional不为空且结果不为null，否则产生一个空Optional。
        Optional<Boolean> added = optionalValue.map(results::add);
        System.out.println(added);

        // <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)  产生将mapper应用于当前的Optional值所产生的结果，
        // 或者在当前Optional为空时，返回一个空Optional。
        System.out.println(inverse(4.0).flatMap(OptionalTest::inverse));
        System.out.println(inverse(-1.0).flatMap(OptionalTest::inverse));
        System.out.println(inverse(0.0).flatMap(OptionalTest::inverse));

        // static <T> Optional<T> of(T value) 产生一个具有给定值的Optional，若value为null，则抛出一个NullPointerException对象。
        // static <T> Optional<T> ofNullable(T value)  产生一个具有给定值的Optional，若为value为null，则产生一个空的Optional。
        Optional<Double> result2 = Optional.of(-4.0).flatMap(OptionalTest::inverse).flatMap(OptionalTest::squareRoot);
        System.out.println(result2);
    }

    private static Optional<Double> squareRoot(Double x) {
        return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
    }

    private static Optional<Double> inverse(double v) {
        return v == 0 ? Optional.empty() : Optional.of(1 / v);
    }
}
